package com.ray.test.proxy;

import com.ray.test.util.AopTargetUtils;
import com.ray.test.util.PropertyUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
import java.util.Map;

/**
 * @author bo shen
 * @Description: 代理类型
 * @Class: ProxyBean
 * @Package com.ray.test.proxy
 * @date 2019/12/13 15:19
 * @company <p>杭州传化陆鲸科技有限公司</p>
 * @updateRecord time(修改时间)  author(修改人)   desc(修改内容)
 */
@Slf4j
public class ProxyBean {

    private Object target;

    private Map<Class<?>, Object> beanService;

    private Map<String, Object> valueService;

    private ApplicationContext applicationContext;


    private Boolean mock = false;

    public ProxyBean(Object proxyBean, Map<Class<?>, Object> beanService, Map<String, Object> valueService) {
        this.target = proxyBean;
        this.beanService = beanService;
        this.valueService = valueService;
        this.mock = false;
    }

    public ProxyBean(Object proxyBean, Map<Class<?>, Object> beanService, Map<String, Object> valueService, ApplicationContext applicationContext) {
        this.target = proxyBean;
        this.beanService = beanService;
        this.valueService = valueService;
        this.applicationContext = applicationContext;
        this.mock = true;
    }

    public ProxyBean(Object proxyBean, ApplicationContext applicationContext) {
        this.target = proxyBean;
        this.applicationContext = applicationContext;
    }

    /**
     *
     * @param flag 是否代理属性对象
     * @return
     */
    public Object create(boolean flag) {
        mockObjectField(target,flag);
        return getRunProxy(target);
    }

    private Object getRunProxy(Object target) {
        Object value = null;
        try {
            if (target.getClass().isInterface()) {
                value = Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),new ParamsHander(applicationContext,target));
            } else {
                //1. 工具类
                Enhancer en = new Enhancer();
                //2. 设置父类
                en.setSuperclass(target.getClass());
                //3. 设置回调函数
                en.setCallback(new ParamsHander(applicationContext,target));
                //4. 创建子类(代理对象)
                value = en.create();
            }
        } catch (Exception e) {
            log.info("代理测试对象异常", e);
        }
        return  value;
    }


    /**
     * 创建mock数据
     *
     * @param value
     */
    private void mockObjectField(Object value,boolean flag) {
        for (Field field : value.getClass().getDeclaredFields()) {
            if (field.isAnnotationPresent(Autowired.class)) {
                init(value, field,flag);
            } else if (field.isAnnotationPresent(Resource.class)) {
                init(value, field,flag);
            } else if (field.isAnnotationPresent(Value.class)) {
                initValue(value, field);
            } else {
                initNewValue(value, field);
            }
        }
    }

    /**
     * @param value
     * @param field
     */
    private void initNewValue(Object value, Field field) {
        try {
            log.info("name:{}",field.getName());
            //静态属性 有值就不处理
            if(Modifier.isStatic(field.getModifiers())){
                return;
            }
            if (!field.getType().isInterface() && !field.getName().startsWith("CGLIB")) {
                //没有默认值才初始化
                Object defaultValue = field.get(value);
                if(defaultValue == null){
                    Object fieldValue = field.getType().newInstance();
                    PropertyUtils.witerProperty(value, field.getName(), fieldValue);
                }else if(mock){
                    PropertyUtils.witerProperty(value, field.getName(), createMockProxyClass(defaultValue,field));
                }
            }
        } catch (Exception e) {
            log.info("属性设置异常,默认构造方法", e);
        }
    }

    /**
     * @param value
     * @param field
     */
    private void initValue(Object value, Field field) {
        if (valueService == null) return;
        try {
            Object fieldValue = valueService.get(field.getName());
            PropertyUtils.witerProperty(value, field.getName(), fieldValue);
        } catch (Exception e) {
            log.info("属性设置异常", e);
        }
    }

    /**
     * @param value
     * @param field
     */
    private void init(Object value, Field field,boolean flag) {
        try {
            Object fieldValue = null;
            if (mock) {
                //通过代理获取对象
                Object bean = null;
                try {
                    if(field.getType() == ApplicationEventPublisher.class){
                        bean = applicationContext;
                    }else {
                        bean = applicationContext.getBean(field.getType());
                    }
                }catch (Exception e){
                    log.info(e.getMessage());
                    bean = applicationContext.getBean(field.getName());
                }
                if(ObjectUtils.isEmpty(bean)){
                    throw  new RuntimeException("属性"+field.getName()+"无法初始化");
                }
                if(flag){
                    bean =  AopTargetUtils.getTarget(bean);
                    fieldValue = createMockProxyClass(bean,field);
                }else {
                    //直接使用spring容器对象
                    fieldValue = bean;
                }
            } else {
                fieldValue = createProxyClass(field);
            }
            PropertyUtils.witerProperty(value, field.getName(), fieldValue);
        } catch (Exception e) {
            log.info("属性设置异常", e);
        }
    }

    private Object createMockProxyClass(Object bean,Field field) {
        Class<?> type = field.getType();
        Object value = null;
        try {
            if (beanService != null) {
                value = beanService.get(type);
            }
            //重新获取属性
            if (value == null) {
                log.info(String.format("属性:[%s]初始化中", type.getTypeName()));
                if (type.isInterface()) {
                    value = Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class<?>[]{type},new MockMethodHander(applicationContext,bean));
                } else {
                    //1. 工具类
                    Enhancer en = new Enhancer();
                    //2. 设置父类
                    en.setSuperclass(type);
                    //3. 设置回调函数
                    en.setCallback(new MockMethodHander(applicationContext,bean));
                    //4. 创建子类(代理对象)
                    value = en.create();
                }
                log.info(String.format("属性:[%s]初始化结束", type.getTypeName()));
            } else {
                log.info(String.format("属性:[%s]初始化成功", type.getTypeName()));
            }
        } catch (Exception e) {
            log.info("属性设置异常", e);
        }
        return value;
    }

    private Object createProxyClass(Field field) {
        Class<?> type = field.getType();
        Object value = null;
        try {
            if (beanService != null) {
                value = beanService.get(field.getType());
            }
            //重新获取属性
            if (value == null) {
                log.info(String.format("属性:[%s],[%s]初始化中", type.getTypeName(), field.getName()));
                if (type.isInterface()) {
                    value = getProxyValue(type);
                } else {
                    value = getCjlibProxyValue(type);
                }
                log.info(String.format("属性:[%s],[%s]初始化结束", type.getTypeName(), field.getName()));
            } else {
                log.info(String.format("属性:[%s],[%s]初始化成功", type.getTypeName(), field.getName()));
            }
        } catch (Exception e) {
            log.info("属性设置异常", e);
        }
        return value;
    }


    /**
     * 通过代理获取对象
     *
     * @param aClass
     * @return
     */
    private <T> T getProxyValue(Class<?> aClass) {
        Object obj = null;
        try {
            obj = java.lang.reflect.Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class<?>[]{aClass}, new Handler(aClass));
        } catch (IllegalArgumentException e) {
            log.info("{}:JDK动态代理创建异常", aClass, e);
        }
        return (T) obj;
    }

    private <T> T getCjlibProxyValue(Class<?> aClass) {
        Object obj = null;
        try {
            //1. 工具类
            Enhancer en = new Enhancer();
            //2. 设置父类
            en.setSuperclass(aClass);
            //3. 设置回调函数
            en.setCallback(new Handler(aClass));
            //4. 创建子类(代理对象)
            obj = en.create();
        } catch (Exception e) {
            log.info("{}:Cl=jlib动态代理创建异常", aClass, e);
        }
        return (T) obj;
    }
}
